const fs = require('fs');
const moment = require('moment');
const path = require('path');
const jsonfile = require('jsonfile');
const DbService = require('./db');

const writeFileSync = (file, params) => {
  let fileData = [];
  if (fs.existsSync(file)) {
    fileData = jsonfile.readFileSync(file) || [];
  }
  fileData.push(params);

  jsonfile.writeFileSync(file, fileData, { spaces: 2 });
};

function isAbsolute(filePath) {
  filePath = path.normalize(filePath);
  if (filePath.substring(0, 1) === '/') return true;
  if (filePath.search(/[\w]+:/) === 0) return true;
  return false;
}
function mkdirSync(dirPath) {
  if (!dirPath) return;
  dirPath = isAbsolute(dirPath) ? path.normalize(dirPath) : path.join(process.cwd(), dirPath);
  if (fs.existsSync(dirPath)) return;

  const arr = dirPath.split(path.sep);
  let index = arr.length - 1;
  let tempStr = arr[index];
  while (tempStr === '' && arr.length > 0) {
    // eslint-disable-next-line no-plusplus
    index--;
    tempStr = arr[index];
  }
  if (tempStr === '') return;
  const newPath = dirPath.substring(0, dirPath.length - tempStr.length - 1);
  if (!fs.existsSync(newPath)) exports.mkdirSync(newPath);
  fs.mkdirSync(dirPath);
}

class LoggerService {
  constructor() {
    if (process.env.REDIS_DB_ENABLE) {
      this.dbService = new DbService();
    }
    this.instance = null;
  }

  static getInstance() {
    if (!this.instance) {
      this.instance = new LoggerService();
    }
    return this.instance;
  }

  getCurrentTime(format) {
    return moment().format(format || 'YYYYMMDDHHmmssSSS');
  }

  async saveLogByType(type, params, writeToDb = true) {
    try {
      params.createAt = this.getCurrentTime('YYYY-MM-DD HH:mm:ss');
      if (this.dbService && writeToDb) {
        return await this.dbService.lPush('logs2', {
          ...params,
          type,
        }, {
          EX: 3 * 24 * 60 * 60,
        });
      }

      const logsPath = path.join(__dirname, '../logs');
      if (!fs.existsSync(logsPath)) {
        mkdirSync(logsPath);
      }
      const logsFilePath = path.join(logsPath, `${type}-log.json`);
      writeFileSync(logsFilePath, params);
    } catch (err) {
      console.error(err);
    }
  }

  async error(params) {
    if (!params) return;

    // 兼容字符串情况
    if (typeof params === 'string') {
      params = {
        errorMsg: params,
      };
    }
    console.error('logger error', params);
    await this.saveLogByType('error', params);
  }

  async info(params) {
    if (!params) return;

    // 兼容字符串情况
    if (typeof params === 'string') {
      params = {
        message: params,
      };
    }
    console.info('logger info', params);
    await this.saveLogByType('info', params);
  }

  /**
   * type: error, callback, info,...
   * @param {*} param0
   */
  async log(params, writeToDb = true) {
    if (typeof params === 'string' || params.type === 'info') {
      return await this.info(params);
    }

    const { type = 'unknown' } = params;
    if (type === 'error') {
      return await this.error(params);
    }

    await this.saveLogByType(type, params, writeToDb);
  }

  async getLogs(params = {}) {
    const { type } = params;
    if (this.dbService) {
      const allLogs = (await this.dbService.lRange('logs2', 0, -1)) || [];
      if (type) {
        return allLogs.filter(item => item.type === type);
      }
      return allLogs;
    }

    // 从本地读取
    const logsFile = path.join(__dirname, `../logs/${type}-log.json`);
    let logs = [];
    if (fs.existsSync(logsFile)) {
      logs = jsonfile.readFileSync(logsFile) || [];
    }
    return logs;
  }

  async clearLogs() {
    if (this.dbService) {
      return this.dbService.del('logs2');
    }
  }
}

module.exports = LoggerService;
